const redis = require('redis');
const { config } = require('../config/config');
const logger = require('./logger');

class CacheManager {
  constructor() {
    this.client = null;
    this.isConnected = false;
    this.defaultTTL = config.cache.ttl;
  }

  // 连接Redis
  async connect() {
    try {
      this.client = redis.createClient({
        socket: {
          host: config.redis.host,
          port: config.redis.port,
          connectTimeout: config.redis.connectTimeout,
          retryDelay: config.redis.retryDelay,
          maxRetries: config.redis.maxRetries
        },
        password: config.redis.password,
        database: config.redis.db
      });

      // 错误处理
      this.client.on('error', (err) => {
        logger.error('Redis连接错误:', err);
        this.isConnected = false;
      });

      this.client.on('connect', () => {
        logger.info('Redis连接成功');
        this.isConnected = true;
      });

      this.client.on('ready', () => {
        logger.info('Redis准备就绪');
      });

      this.client.on('end', () => {
        logger.info('Redis连接关闭');
        this.isConnected = false;
      });

      await this.client.connect();
      return true;
    } catch (error) {
      logger.error('Redis连接失败:', error);
      return false;
    }
  }

  // 断开连接
  async disconnect() {
    if (this.client && this.isConnected) {
      await this.client.quit();
      this.isConnected = false;
    }
  }

  // 设置缓存
  async set(key, value, ttl = this.defaultTTL) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const serializedValue = typeof value === 'object' ? JSON.stringify(value) : value;
      await this.client.setEx(key, ttl, serializedValue);
      
      logger.debug(`缓存设置成功: ${key}`);
      return true;
    } catch (error) {
      logger.error(`缓存设置失败: ${key}`, error);
      return false;
    }
  }

  // 获取缓存
  async get(key) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const value = await this.client.get(key);
      
      if (value === null) {
        logger.debug(`缓存未找到: ${key}`);
        return null;
      }

      // 尝试解析JSON
      try {
        return JSON.parse(value);
      } catch {
        return value;
      }
    } catch (error) {
      logger.error(`缓存获取失败: ${key}`, error);
      return null;
    }
  }

  // 删除缓存
  async del(key) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const result = await this.client.del(key);
      logger.debug(`缓存删除成功: ${key}`);
      return result > 0;
    } catch (error) {
      logger.error(`缓存删除失败: ${key}`, error);
      return false;
    }
  }

  // 批量删除缓存
  async delPattern(pattern) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const keys = await this.client.keys(pattern);
      if (keys.length > 0) {
        await this.client.del(keys);
        logger.debug(`批量删除缓存成功: ${pattern}, 删除数量: ${keys.length}`);
      }
      return keys.length;
    } catch (error) {
      logger.error(`批量删除缓存失败: ${pattern}`, error);
      return 0;
    }
  }

  // 检查缓存是否存在
  async exists(key) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const result = await this.client.exists(key);
      return result > 0;
    } catch (error) {
      logger.error(`检查缓存存在失败: ${key}`, error);
      return false;
    }
  }

  // 设置缓存过期时间
  async expire(key, ttl) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const result = await this.client.expire(key, ttl);
      return result > 0;
    } catch (error) {
      logger.error(`设置缓存过期时间失败: ${key}`, error);
      return false;
    }
  }

  // 获取缓存剩余时间
  async ttl(key) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      return await this.client.ttl(key);
    } catch (error) {
      logger.error(`获取缓存剩余时间失败: ${key}`, error);
      return -1;
    }
  }

  // 递增计数器
  async incr(key, ttl = this.defaultTTL) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const result = await this.client.incr(key);
      await this.expire(key, ttl);
      return result;
    } catch (error) {
      logger.error(`递增计数器失败: ${key}`, error);
      return null;
    }
  }

  // 递减计数器
  async decr(key, ttl = this.defaultTTL) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const result = await this.client.decr(key);
      await this.expire(key, ttl);
      return result;
    } catch (error) {
      logger.error(`递减计数器失败: ${key}`, error);
      return null;
    }
  }

  // 设置哈希表
  async hset(key, field, value, ttl = this.defaultTTL) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const serializedValue = typeof value === 'object' ? JSON.stringify(value) : value;
      await this.client.hSet(key, field, serializedValue);
      await this.expire(key, ttl);
      
      logger.debug(`哈希表设置成功: ${key}.${field}`);
      return true;
    } catch (error) {
      logger.error(`哈希表设置失败: ${key}.${field}`, error);
      return false;
    }
  }

  // 获取哈希表字段
  async hget(key, field) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const value = await this.client.hGet(key, field);
      
      if (value === null) {
        return null;
      }

      // 尝试解析JSON
      try {
        return JSON.parse(value);
      } catch {
        return value;
      }
    } catch (error) {
      logger.error(`哈希表获取失败: ${key}.${field}`, error);
      return null;
    }
  }

  // 获取哈希表所有字段
  async hgetall(key) {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const result = await this.client.hGetAll(key);
      const parsed = {};

      for (const [field, value] of Object.entries(result)) {
        try {
          parsed[field] = JSON.parse(value);
        } catch {
          parsed[field] = value;
        }
      }

      return parsed;
    } catch (error) {
      logger.error(`获取哈希表所有字段失败: ${key}`, error);
      return {};
    }
  }

  // 缓存装饰器
  static cache(ttl = null, keyGenerator = null) {
    return function (target, propertyName, descriptor) {
      const method = descriptor.value;

      descriptor.value = async function (...args) {
        const cacheKey = keyGenerator ? keyGenerator(...args) : `${target.constructor.name}:${propertyName}:${JSON.stringify(args)}`;
        const cacheTtl = ttl || this.defaultTTL;

        // 尝试从缓存获取
        const cached = await this.get(cacheKey);
        if (cached !== null) {
          return cached;
        }

        // 执行原方法
        const result = await method.apply(this, args);

        // 缓存结果
        await this.set(cacheKey, result, cacheTtl);

        return result;
      };

      return descriptor;
    };
  }

  // 获取缓存统计信息
  async getStats() {
    try {
      if (!this.isConnected) {
        throw new Error('Redis未连接');
      }

      const info = await this.client.info();
      const keys = await this.client.dbSize();
      
      return {
        connected: this.isConnected,
        keys,
        info: info.split('\r\n').reduce((acc, line) => {
          const [key, value] = line.split(':');
          if (key && value) {
            acc[key] = value;
          }
          return acc;
        }, {})
      };
    } catch (error) {
      logger.error('获取缓存统计信息失败:', error);
      return {
        connected: this.isConnected,
        keys: 0,
        info: {}
      };
    }
  }
}

// 创建全局缓存实例
const cacheManager = new CacheManager();

module.exports = {
  CacheManager,
  cacheManager
}; 